在 C++ 中,每個運算式都會產生一個 左值 或一個 右值。這個區別決定了運算式是參考物件的 身份 (位置在哪裡)還是其 值 (內容是什麼)。
1. 身份與內容的區別
一個 左值 (定位值)代表具有持久記憶體位址的物件。可將其想像成記憶體中的一個標籤盒。相反地,一個 右值 (讀取值)是暫時性的;它代表一個暫時結果或常數字面量,而該值對程式設計師來說沒有可存取的位址。
2. 功能性轉換
雖然左值可以當作右值使用(編譯器只需取出盒子內的值),但反過來則被禁止。你無法在需要左值的地方使用右值——例如,你不能對像 &42 這樣的常數字面量取位址,因為它缺乏持久的身份。
$$ \text{左值} \xrightarrow{\text{轉換}} \text{右值} \quad (\text{允許}) $$
$$ \text{右值} \xrightarrow{\text{賦值}} \text{左值} \quad (\text{禁止}) $$
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
Which of the following best describes an lvalue?
A temporary result of a calculation.
An expression that yields an object with a persistent memory identity.
A literal constant like 3.14.
Any value that appears on the right side of an assignment.
✅ Correct!
Correct! Lvalues represent 'locatable' objects that reside in memory.❌ Incorrect
Lvalues are about identity (memory address). Literals and temporary results are typically rvalues.QUESTION 2
In the expression
dval = ival = 0;, why is 0 considered an rvalue?Because it is an integer.
Because it is on the far right of the expression.
Because it is a literal constant with no persistent memory address.
Because it is assigned to
pi.✅ Correct!
Exactly. Literals are values without a user-accessible memory identity.❌ Incorrect
The position doesn't determine lvalue/rvalue status; the nature of the expression (identity vs. value) does.QUESTION 3
True or False: You can use an rvalue where an lvalue is required.
True
False
✅ Correct!
False is correct. Operators like assignment (=) and address-of (&) require lvalues.❌ Incorrect
Rvalues cannot be used when the compiler needs a specific memory location to write to or point at.QUESTION 4
What happens when you use an lvalue in a context that requires an rvalue?
A compile-time error occurs.
The compiler performs an lvalue-to-rvalue conversion.
The memory address of the lvalue is used as the value.
The lvalue is deleted from memory.
✅ Correct!
The compiler simply fetches the value stored at that identity to use in the expression.❌ Incorrect
C++ is designed to allow lvalues to be used as rvalues seamlessly.QUESTION 5
Which of these expressions is an lvalue?
42x + y (where x and y are ints)std::string("hello")A variable name like
myVar✅ Correct!
Variable names are the most common lvalues because they refer directly to a persistent object.❌ Incorrect
Literals, arithmetic results, and temporary objects are rvalues.Comprehensive Expression Analysis
Applying Lvalue/Rvalue theory to Exercise 5.23 and 4.2
As a C++ developer, you must evaluate how expressions are grouped and whether their operands are valid based on their identity and value types. Consider the following definitions: int i; double d; const string *ps; char *pc; void *pv; vector<int> vec = {10, 20};
Q
1. [Exercise 5.23] Provide a program that safely reads two integers and prints the result of their division. What role do lvalues play here?
Solution:
Model Solution: cpp int n1, n2; if (std::cin >> n1 >> n2) { if (n2 != 0) std::cout << n1 / n2 << std::endl; else std::cerr << "Division by zero!" << std::endl; } In this program, `n1` and `n2` are lvalues used to store input. In the expression `n1 / n2`, they undergo lvalue-to-rvalue conversion to provide their contents for the arithmetic operation.
Model Solution: cpp int n1, n2; if (std::cin >> n1 >> n2) { if (n2 != 0) std::cout << n1 / n2 << std::endl; else std::cerr << "Division by zero!" << std::endl; } In this program, `n1` and `n2` are lvalues used to store input. In the expression `n1 / n2`, they undergo lvalue-to-rvalue conversion to provide their contents for the arithmetic operation.
Q
2. [Exercise 4.2] Parenthesize the expressions `* vec.begin()` and `* vec.begin() + 1`. Identify which parts are lvalues.
Solution:
Parenthesization: (a) `*(vec.begin())`: The `.` operator has higher precedence than `*`. `vec.begin()` returns an iterator (rvalue), and dereferencing it yields an lvalue (the first element of the vector). (b) `(*(vec.begin())) + 1`: The addition occurs after dereferencing. The result of the addition is an rvalue (a temporary numerical result).
Parenthesization: (a) `*(vec.begin())`: The `.` operator has higher precedence than `*`. `vec.begin()` returns an iterator (rvalue), and dereferencing it yields an lvalue (the first element of the vector). (b) `(*(vec.begin())) + 1`: The addition occurs after dereferencing. The result of the addition is an rvalue (a temporary numerical result).
Q
3. [Theory Depth] Why does `&42` fail while `&ival` succeeds?
Solution:
The address-of operator (`&`) requires an lvalue operand. `42` is a literal rvalue with no persistent location in memory to point to. `ival` is an lvalue representing a specific, identifiable memory address, so the operator can successfully return that address.
The address-of operator (`&`) requires an lvalue operand. `42` is a literal rvalue with no persistent location in memory to point to. `ival` is an lvalue representing a specific, identifiable memory address, so the operator can successfully return that address.